﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PlanningGIS.ArcGIS.Custom;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
using PlanningGIS.Util;
using System.Runtime.InteropServices;
using ESRI.ArcGIS.Carto;
using System.Text.RegularExpressions;
using PlanningGIS.Win.Controls;

namespace PlanningGIS.MapSheet
{
    /// <summary>
    /// 图幅抽象基类，不能直接使用。
    /// 以国家标准图幅计算公式为准，得到1：100万，到1：5千经纬度下的标准图幅。
    /// 注：图幅命名规则为从上到下、从左到右。
    /// 1位1：100万图幅行号（字符码）+ 2位1：100万图幅列号（数字码）+ 1位比例尺代码 + 3位图幅行号（数字码）+ 3位图幅列号（数字码）
    /// </summary>
    public abstract class BaseMapsheet
    {
        /// <summary>
        /// 图幅字符编码常量
        /// </summary>
        public readonly string[] SheetCharCodes = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V" };

        /// <summary>
        /// 构造函数
        /// </summary>
        public BaseMapsheet()
        {
            XDiff = 250;
            YDiff = 250;
            ColLength = 1;
            RowLength = 1;
            OffsetLen = 0;
        }

        /// <summary>
        /// 外扩距离，单位公里
        /// </summary>
        public double OffsetLen { get; set; }
        
        /// <summary>
        /// 经度差
        /// </summary>
        protected const double LonDiff = 6.0;

        /// <summary>
        /// 纬度差
        /// </summary>
        protected const double LatDiff = 4.0;

        /// <summary>
        /// x方向500图幅的差
        /// </summary>
        protected double XDiff = 250;

        /// <summary>
        /// y方向500图幅的差
        /// </summary>
        protected double YDiff = 250;

        /// <summary>
        /// 图幅宽度
        /// </summary>
        public double Width { get; set; }

        /// <summary>
        /// 图幅高度
        /// </summary>
        public double Height { get; set; }  
      
        /// <summary>
        /// 横向分幅的个数
        /// </summary>
        public int ColLength { get; protected set; }

        /// <summary>
        /// 纵向分幅的个数
        /// </summary>
        public int RowLength { get; protected set; }

        /// <summary>
        /// 获取横向图幅的总数
        /// </summary>
        public int ColCount { get; protected set; }

        /// <summary>
        /// 获取纵向图幅的总数
        /// </summary>
        public int RowCount { get; protected set; }

        /// <summary>
        /// 单位值：1000米；100米；10米； 1米
        /// </summary>
        public int UnitValue { get; set; }

        /// <summary>
        /// 获取或设置图幅大小字符串
        /// </summary>
        public string SizeString
        {
            get
            {
                return XDiff.ToString() + "X" + YDiff.ToString();
            }
            set
            {
                string[] vs = value.ToUpper().Split('X');
                XDiff = double.Parse(vs[0]);
                YDiff = double.Parse(vs[1]);
            }
        }

        /// <summary>
        /// 进度条
        /// </summary>
        public Progressor _Progressor { get; set; }
        
        /// <summary>
        /// 空间比较对象
        /// </summary>
        public IRelationalOperator RelationalGeometry { get; protected set; }

        /// <summary>
        /// 空间比较数据集
        /// </summary>
        public IFeatureClass RelationalFeatureClass { get; protected set; }

        /// <summary>
        /// 获取图幅全图最小的X坐标
        /// </summary>
        public double XMin { get; protected set; }
        /// <summary>
        /// 获取图幅全图最小的Y坐标
        /// </summary>
        public double YMin { get; protected set; }
        /// <summary>
        /// 获取图幅全图最大的X坐标
        /// </summary>
        public double XMax { get; protected set; }
        /// <summary>
        /// 获取图幅全图最大的Y坐标
        /// </summary>
        public double YMax { get; protected set; }

        protected bool _IsGeo = false;
        
        /// <summary>
        /// 根据空间对象创建满足国家标准的图幅
        /// </summary>
        /// <param name="extent">要创建图幅的空间范围：矩形</param>
        /// <param name="sheetFeatureClass">要创建到的图幅图层</param>
        /// <param name="fIndex">图幅名称字段</param>
        /// <param name="scale">要创建图幅的比例尺</param>
        /// <param name="removespace">是否移除与空间对象不想交的空白图幅。默认为false：不移除</param>
        /// <returns>true创建成功；false创建失败</returns>
        protected bool CreateBaseSheet(IEnvelope extent, IFeatureClass sheetFeatureClass, int fIndex, SheetScale scale, bool removespace = false)
        {
            SetSize(scale);
            string scalecode = GetScaleCode(scale);
            string sheetcode = this.MathSheetCode(extent.XMin, extent.YMin, scalecode);
            IPoint ptmin = this.MathBaseWSPoint(sheetcode);
            ColCount = (int)Math.Ceiling(((extent.XMax + Width) - ptmin.X) / Width);
            RowCount = (int)Math.Ceiling(((extent.YMax + Height) - ptmin.Y) / Height);
            if (_Progressor != null) _Progressor.SetMaxValue(ColCount * RowCount);
            IFeatureCursor featCursor = sheetFeatureClass.Insert(true);
            int index = 0;
            IRelationalOperator relOp = extent as IRelationalOperator;
            object missing = Type.Missing;
            for (double x = ptmin.X; x <= (extent.XMax + Width); x += Width)
            {
                for (double y = ptmin.Y; y <= (extent.YMax + Height); y += Height)
                {
                    //直接以左下角点计算时，可能会由于经度的问题导致计算出现偏差
                    string mapno = this.MathSheetCode(x + 0.00005, y + 0.00005, scalecode);
                    index++;
                    if (_Progressor != null)
                        _Progressor.SetCurrentValue(index);
                    double temy = y;
                    for (int m = RowLength; m > 0; m--)
                    {
                        double tmpx = x;
                        for (int n = 1; n <= ColLength; n++)
                        {
                            int nm = n + (m - 1) * 3;
                            string tmpno = mapno;
                            if (RowLength != 1 && ColLength != 1)
                                tmpno += "-" + nm.ToString();
                            IPolygon polygon = this.CreateGeometry(tmpx, temy, Width/ColLength, Height/RowLength, scale);
                            tmpx += Width / ColLength;
                            if (scale.Value == 2000)
                                if (relOp.Disjoint(polygon))
                                    continue;
                            if (removespace)
                                if (Disjoint(polygon))
                                    continue;
                            IFeatureBuffer featureBuffer = sheetFeatureClass.CreateFeatureBuffer();
                            featureBuffer.Shape = polygon;
                            featureBuffer.set_Value(fIndex, tmpno);
                            featCursor.InsertFeature(featureBuffer);
                        }
                        temy += Height / RowLength;
                    }
                    if (index % 1000 == 0)
                        featCursor.Flush();
                }
            }
            featCursor.Flush();
            Marshal.ReleaseComObject(featCursor);
            featCursor = null;
            if (_Progressor != null) _Progressor.Stop();
            return true;
        }

        /// <summary>
        /// 创建图幅空间对象
        /// </summary>
        /// <param name="x">西南角（左下角）点经度</param>
        /// <param name="y">西南角（左下角）点纬度</param>
        /// <param name="width">图幅宽度</param>
        /// <param name="height">图幅高度</param>
        /// <param name="scale">比例尺对象</param>
        /// <returns></returns>
        protected IPolygon CreateGeometry(double x, double y, double width, double height, SheetScale scale)
        {
            object missing = Type.Missing;
            IPolygon polygon = new Polygon() as IPolygon;
            IPointCollection pColl = polygon as IPointCollection;

            IPoint pt = new Point();
            pt.PutCoords(x, y);
            pColl.AddPoint(pt, ref missing, ref missing);

            if (scale.Value > 5000)
            {
                pt = new Point();
                pt.PutCoords(x, y + height * 0.5);
                pColl.AddPoint(pt, ref missing, ref missing);
            }
            pt = new Point();
            pt.PutCoords(x, y + height);
            pColl.AddPoint(pt, ref missing, ref missing);

            if (scale.Value > 5000)
            {
                pt = new Point();
                pt.PutCoords(x + width * 0.5, y + height);
                pColl.AddPoint(pt, ref missing, ref missing);
            }

            pt = new Point();
            pt.PutCoords(x + width, y + height);
            pColl.AddPoint(pt, ref missing, ref missing);

            if (scale.Value > 5000)
            {
                pt = new Point();
                pt.PutCoords(x + width, y + height * 0.5);
                pColl.AddPoint(pt, ref missing, ref missing);
            }

            pt = new Point();
            pt.PutCoords(x + width, y);
            pColl.AddPoint(pt, ref missing, ref missing);

            if (scale.Value > 5000)
            {
                pt = new Point();
                pt.PutCoords(x + width * 0.5, y);
                pColl.AddPoint(pt, ref missing, ref missing);
            }

            pt = new Point();
            pt.PutCoords(x, y);
            pColl.AddPoint(pt, ref missing, ref missing);
            return polygon;
        }

        /// <summary>
        /// 根据图幅号获取图幅对象
        /// </summary>
        /// <param name="sheetcode">带有比例尺标识的图幅号</param>
        /// <returns></returns>
        public Mapsheet GetMapSheet(string sheetcode)
        {
            if (string.IsNullOrWhiteSpace(sheetcode))
                throw new Exception("图号不能为空");
            SheetScale scale = GetScaleByCode(sheetcode);
            if (scale == null || scale.Index < 0)
                throw new Exception("图号" + sheetcode + "不是标准格式，请使用");
            SetSize(scale);
            IPoint p = MathBaseWSPoint(sheetcode);
            return new Mapsheet()
            {
                Code = sheetcode,
                Geometry = CreateGeometry(p.X, p.Y, Width / ColLength, Height / RowLength, scale)
            };
        }

        /// <summary>
        /// 根据图幅号获取西南角（左下角）点的坐标
        /// </summary>
        /// <param name="sheetcode">带有比例尺标识的图幅号</param>
        /// <returns></returns>
        public IPoint GetWestSouthPoint(string sheetcode)
        {
            if (string.IsNullOrWhiteSpace(sheetcode))
                throw new Exception("图号不能为空");
            SheetScale scale = GetScaleByCode(sheetcode);
            if (scale == null || scale.Index < 0)
                throw new Exception("图号" + sheetcode + "不是标准格式，请使用");
            SetSize(scale);
            return MathBaseWSPoint(sheetcode);
        }

        /// <summary>
        /// 根据坐标获取图幅，若坐标点为角点时，则坐标应为左上角点
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="scale"></param>
        /// <returns></returns>
        protected Mapsheet GetBaseSheet(double x, double y, SheetScale scale)
        {
            string scalecode = GetScaleCode(scale);
            string sheetcode = MathSheetCode(x, y, scalecode);
            IPoint ptmin = MathBaseWSPoint(sheetcode);
            double newX = ptmin.X;
            double newY = ptmin.Y;
            if (scale.Value == 2000)
            {
                int xn = Math.Abs((int)Math.Ceiling((x - ptmin.X) / (Width / 3)));
                int ym = Math.Abs(((int)Math.Ceiling((ptmin.Y + Height - y) / (Height / 3))));
                sheetcode = sheetcode + "-" + (xn + (ym - 1) * 3).ToString();
            }
            return new Mapsheet()
            {
                Code = sheetcode,
                Geometry = CreateGeometry(newX, newY, Width / ColLength, Height / RowLength, scale)
            };
        }

        /// <summary>
        /// 根据图号获取其四周8个方向的图幅与自身所在的图幅，按从上到下，从左到右排列
        /// </summary>
        /// <param name="sheetcode">图号</param>
        /// <returns></returns>
        public List<Mapsheet> GetMapSheets(string sheetcode)
        {
            SheetScale scale = GetScaleByCode(sheetcode);
            if (scale.Index<0)
                throw new Exception("编号" + sheetcode + "不是标准的图幅编号，无法根据编号计算");
            SetSize(scale);
            IPoint pt = MathBaseWSPoint(sheetcode);
            return GetBaseSheets(pt.X, pt.Y + Height / RowLength, scale);
        }

        /// <summary>
        /// 获取空间对象所在的图幅集合对象
        /// </summary>
        /// <param name="geometry">空间范围</param>
        /// <param name="scale">对应的比例尺</param>
        /// <param name="removespace">是否移除与空间对象不想交的图幅。默认为true：移除</param>
        /// <returns></returns>
        public List<Mapsheet> GetBaseSheets(IGeometry geometry, SheetScale scale, bool removespace = true)
        {
            string scalecode = GetScaleCode(scale);
            List<Mapsheet> lst = new List<Mapsheet>();
            string sheetcode = this.MathSheetCode(geometry.Envelope.XMin, geometry.Envelope.YMin, scalecode);
            IPoint ptmin = this.MathBaseWSPoint(sheetcode);
            IRelationalOperator relOp = geometry as IRelationalOperator;
            object missing = Type.Missing;
            for (double x = ptmin.X; x <= geometry.Envelope.XMax; x += Width)
            {
                for (double y = ptmin.Y; y <= geometry.Envelope.YMax; y += Height)
                {
                    string mapno = this.MathSheetCode(x, y + Height, scalecode);
                    double temy = y;
                    for (int m = RowLength; m > 0; m--)
                    {
                        double tmpx = x;
                        for (int n = 1; n <= ColLength; n++)
                        {
                            int nm = n + (m - 1) * 3;
                            string tmpno = mapno;
                            if (RowLength != 1 && ColLength != 1)
                                tmpno += "-" + nm.ToString();
                            IPolygon polygon = this.CreateGeometry(tmpx, temy, Width / ColLength, Height / RowLength, scale);
                            tmpx += Width / ColLength;
                            if (scale.Value == 2000)
                                if (relOp.Disjoint(polygon))
                                    continue;
                            if (removespace)
                                if (Disjoint(polygon))
                                    continue;
                            lst.Add(new Mapsheet()
                            {
                                Code = tmpno,
                                Geometry = polygon
                            });
                        }
                        temy += Height / RowLength;
                    }
                }
            }
            return lst;
        }
        
        /// <summary>
        /// 根据坐标点获取其四周8个方向的图幅与自身所在的图幅，按从上到下，从左到右排列
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="scale">比例尺</param>
        /// <returns></returns>
        protected List<Mapsheet> GetBaseSheets(double x, double y, SheetScale scale)
        {
            Mapsheet tf = this.GetBaseSheet(x, y, scale);
            if (tf == null)
                return null;
            double newx = tf.Geometry.Envelope.LowerLeft.X;
            double newy = tf.Geometry.Envelope.LowerLeft.Y;
            List<Mapsheet> tfs = new List<Mapsheet>();
            tfs.Add(this.GetBaseSheet(newx - Width/ColLength, newy + 2 * Height/RowLength,  scale));
            tfs.Add(this.GetBaseSheet(newx, newy + 2 * Height / RowLength, scale));
            tfs.Add(this.GetBaseSheet(newx + Width / ColLength, newy + 2 * Height / RowLength, scale));

            tfs.Add(this.GetBaseSheet(newx - Width / ColLength, newy + Height / RowLength, scale));
            tfs.Add(tf);
            tfs.Add(this.GetBaseSheet(newx + Width / ColLength, newy + Height / RowLength, scale));

            tfs.Add(this.GetBaseSheet(newx - Width / ColLength, newy, scale));
            tfs.Add(this.GetBaseSheet(newx, newy, scale));
            tfs.Add(this.GetBaseSheet(newx + Width / ColLength, newy, scale));

            return tfs;
        }

        /// <summary>
        /// 是否为标准的图幅号
        /// </summary>
        /// <param name="sheetcode"></param>
        /// <returns></returns>
        public bool IsGBCode(string sheetcode)
        {
            SheetScale scale = GetScaleByCode(sheetcode);
            if (scale == null || scale.Index < 0)
                return false;
            return true;
        }

        /// <summary>
        /// 设置图幅的大小
        /// </summary>
        /// <param name="scale">比例尺类型</param>
        protected void SetSize(SheetScale scale)
        {
            if (string.IsNullOrEmpty(scale.Format) || string.IsNullOrWhiteSpace(scale.Format))
            {
                Width = LonDiff / scale.SheetCount;
                Height = LatDiff / scale.SheetCount;
                RowLength = 1;
                ColLength = 1;
                if (scale.Value == 2000)
                {
                    SheetScale newscale = SheetScale.Create(5000);
                    Width = LonDiff / newscale.SheetCount;
                    Height = LatDiff / newscale.SheetCount;
                    RowLength = 3;
                    ColLength = 3;
                }
            }
            else
            {
                switch (scale.Value)
                {
                    case 500:
                        Width = XDiff;
                        Height = YDiff;
                        break;
                    case 1000:
                        Width = XDiff * 2;
                        Height = YDiff * 2;
                        break;
                    case 2000:
                        Width = XDiff * 4;
                        Height = YDiff * 4;
                        break;
                    case 5000:
                        Width = XDiff * 10;
                        Height = YDiff * 10;
                        break;
                    case 10000:
                        Width = XDiff * 20;
                        Height = YDiff * 20;
                        break;
                    default:
                        throw new Exception("值" + scale.Value.ToString() + "非标准的比例尺，请重新设置");
                }
                ColLength = 1;
                RowLength = 1;
                if (scale.ParentValue > 0)
                {
                    ColLength = scale.ParentValue / scale.Value;
                    RowLength = ColLength;
                    Width = Width * ColLength;
                    Height = Height * RowLength;
                }
            }
        }

        /// <summary>
        /// 设置图幅范围，需要先设置图幅大小SetSize
        /// </summary>
        /// <param name="extent">全图范围</param>
        protected void SetFullExtent(IEnvelope extent)
        {
            if (extent == null)
                return;
            XMin = GetFloor(extent.XMin - OffsetLen * 1000, (int)Width);
            YMin = GetFloor(extent.YMin - OffsetLen * 1000, (int)Height);
            XMax = GetCeiling(extent.XMax + OffsetLen * 1000, (int)Width);
            YMax = GetCeiling(extent.YMax + OffsetLen * 1000, (int)Height);
            ColCount = (int)(XMax - XMin) / (int)Width;
            RowCount = (int)(YMax - YMin) / (int)Height;
        }
        
        /// <summary>
        /// 根据图号获取比例尺对象
        /// </summary>
        /// <param name="sheetcode">图号</param>
        /// <returns></returns>
        protected SheetScale GetScaleByCode(string sheetcode)
        {
            int len = sheetcode.Trim().Length;
            if (len != 3 && len != 10 && len != 12)
                return null;
            string s = SheetCharCodes.FirstOrDefault(t => t.Equals(sheetcode.Trim().Substring(0, 1), StringComparison.CurrentCultureIgnoreCase));
            if (string.IsNullOrEmpty(s))
                return null;
            double d = 0;
            if (!double.TryParse(sheetcode.Trim().Substring(1, 2), out d))
                return null;
            if (d > 60 || d < 1)
                return null;
            string scalecode = sheetcode.Substring(3, 1).ToUpper();
            SheetScale scale = SheetScale.Create(scalecode);
            if (scale != null && scale.Index >= 0)
                return scale;
            if (len >= 10 )
            {
                scale = SheetScale.Create(2000);
            }
            return scale;
        }
                
        /// <summary>
        /// 获取比例尺编码，加此方法是因为存在比例尺分幅的情况
        /// </summary>
        /// <param name="scale"></param>
        /// <returns></returns>
        private string GetScaleCode(SheetScale scale)
        {
            string scalecode = scale.Code;
            if (scale.Value == 2000)
            {
                SheetScale newscale = SheetScale.Create(5000);
                scalecode = newscale.Code;
            }
            return scalecode;
        }
        
        /// <summary>
        /// 根据图号格式获取图号
        /// </summary>
        /// <param name="x">左下角x坐标</param>
        /// <param name="y">左下角y坐标</param>
        /// <param name="format">图号格式</param>
        /// <param name="XOffset">x偏移量</param>
        /// <param name="YOffset">y偏移量</param>
        /// <returns></returns>
        protected string GetFormatCode(double x, double y, string format, double XOffset = 0, double YOffset=0)
        {
            string xStr = ((x - XOffset) / UnitValue).ToString();
            string yStr = ((y - YOffset) / UnitValue).ToString();
            if (string.IsNullOrWhiteSpace(format) || string.IsNullOrEmpty(format))
            {
                return yStr + "-" + xStr;
            }
            string code = format;
            if (format.Contains("DX"))
            {
                code = code.Replace("DX", xStr);
            }
            if (format.Contains("DY"))
            {
                code = code.Replace("DY", yStr);
            }
            string sYY = GetMatchString(format, "Y");
            string syy = GetMatchString(format, "y");
            string sXX = GetMatchString(format, "X");
            string sxx = GetMatchString(format, "x");
            if (!string.IsNullOrWhiteSpace(sYY) && !string.IsNullOrEmpty(sYY) && !format.Contains("DY"))
            {
                string[] Yy = yStr.ToString().Split('.');
                string YY = Yy[0].PadLeft(sYY.Length, '0');
                if (Yy[0].StartsWith("-"))
                    YY = "-" + Yy[0].Substring(1).PadLeft(sYY.Length, '0');
                string yy = Yy.Length == 1 ? "0".PadRight(syy.Length, '0') : Yy[1].PadRight(syy.Length, '0');
                if (syy.Length > 0)
                    code = code.Replace(syy, yy);
                if (sYY.Length>0)
                    code = code.Replace(sYY, YY);
            }
            if (!string.IsNullOrWhiteSpace(sXX) && !string.IsNullOrEmpty(sXX) && !format.Contains("DX"))
            {
                string[] Xx = xStr.ToString().Split('.');
                string XX = Xx[0].PadLeft(sXX.Length, '0');
                if (Xx[0].StartsWith("-"))
                    XX = "-" + Xx[0].Substring(1).PadLeft(sXX.Length, '0');
                string xx = Xx.Length == 1 ? "0".PadRight(sxx.Length, '0') : Xx[1].PadRight(sxx.Length, '0');
                if (sxx.Length > 0)
                    code = code.Replace(sxx, xx);
                if (sXX.Length > 0)
                    code = code.Replace(sXX, XX);      
            }
            return code;
        }

        /// <summary>
        /// 检查图号是否正确，正确则返回true
        /// </summary>
        /// <param name="code">图号</param>
        /// <param name="format">图号格式，不能为空</param>
        /// <param name="x">图号所表示的X坐标</param>
        /// <param name="y">图号所表示的Y坐标</param>
        /// <param name="XOffset">X偏移量</param>
        /// <param name="YOffset">Y偏移量</param>
        /// <returns></returns>
        protected bool CheckFormatCode(string code, string format, out double x, out double y, double XOffset = 0, double YOffset = 0)
        {
            x = 0;
            y = 0;
            if (string.IsNullOrWhiteSpace(format) || string.IsNullOrEmpty(format)) return false; //格式不能为空
            // 格式: DY [*] DX 或 DX [*] DY ,[*]通配符
            if (format.Contains("DX") || format.Contains("DY"))
            {
                x = GetXYCoor(code, format, "DX", XOffset);
                if (x < 0) return false;
                y = GetXYCoor(code, format, "DY", YOffset);
                if (y < 0) return false;
            }

            // 格式:  Yy [*] Xx 或 Xx [*] Yy  ,[*]通配符
            char[] fs = format.ToCharArray();
            string qz = "";
            for (int i = 0; i < fs.Length; i++)
            {
                if (fs[i] == 'Y' || fs[i] == 'X' || fs[i] == 'D') break;
                qz += Convert.ToString(fs[i]);
            }
            format = format.Trim().Substring(qz.Length);
            code = code.Trim().Substring(qz.Length);
            bool isFH = code.StartsWith("-");
            if (isFH) code = code.Substring(1);
            string sYY = GetMatchString(format, "Y");
            string syy = GetMatchString(format, "y");
            string sXX = GetMatchString(format, "X");
            string sxx = GetMatchString(format, "x");
            int YYIndex = format.IndexOf(sYY);
            int XXIndex = format.IndexOf(sXX);

            if (Math.Abs((code.Length - format.Length)) > 2 )
                throw new Exception("图号命名格式与图号不对应，请检查图号命名格式");

            if (YYIndex < XXIndex) // Y-X
            {
                string YY = code.Substring(YYIndex, sYY.Length);
                if (syy.Length > 0)
                {
                    int yyIndex = format.IndexOf(syy);
                    string yy = code.Substring(yyIndex, syy.Length);
                    YY += "." + yy;
                }
                if (!double.TryParse(YY, out y)) return false;
                if (isFH) y = y * (-1);
                y = y * UnitValue + YOffset;

                isFH = false;
                if (code.Length > format.Length)
                {
                    if ((code.Length - format.Length) != 1) return false;
                    isFH = true;
                }
                string XX = isFH ? code.Substring(XXIndex + 1, sXX.Length) : code.Substring(XXIndex, sXX.Length);
                if (sxx.Length > 0)
                {
                    int xxIndex = format.IndexOf(sxx);
                    string xx = isFH ? code.Substring(xxIndex + 1, sxx.Length) : code.Substring(xxIndex, sxx.Length);
                    XX += "." + xx;
                }
                if (!double.TryParse(XX, out x)) return false;
                if (isFH) x = x * (-1);
                x = x * UnitValue + XOffset;
            }
            else // X-Y
            {
                string XX = code.Substring(XXIndex, sXX.Length);
                if (sxx.Length > 0)
                {
                    int xxIndex = format.IndexOf(sxx);
                    string xx = code.Substring(xxIndex, sxx.Length);
                    XX += "." + xx;
                }
                if (!double.TryParse(XX, out x)) return false;
                if (isFH) x = x * (-1);
                x = x * UnitValue + XOffset;

                isFH = false;
                if (code.Length > format.Length)
                {
                    if ((code.Length - format.Length) != 1) return false;
                    isFH = true;
                }
                string YY = isFH ? code.Substring(YYIndex + 1, sYY.Length) : code.Substring(YYIndex, sYY.Length);
                if (syy.Length > 0)
                {
                    int yyIndex = format.IndexOf(syy);
                    string yy = isFH ? code.Substring(yyIndex + 1, syy.Length) : code.Substring(yyIndex, syy.Length);
                    YY += "." + yy;
                }
                if (!double.TryParse(YY, out y)) return false;
                if (isFH) y = y * (-1);
                y = y * UnitValue + YOffset;
            }
            return true;
        }
        
        /// <summary>
        /// 根据图号格式分割图号，获取对应的X、Y的值
        /// </summary>
        /// <param name="code">图号</param>
        /// <param name="format">图号格式</param>
        /// <param name="spvalue">图号格式X、Y的标识符</param>
        /// <param name="offset">X、Y的偏移量</param>
        /// <returns></returns>
        private double GetXYCoor(string code, string format, string spvalue, double offset = 0)
        {
            string sp = "-";
            int index = 0;
            if (format.StartsWith(spvalue))
            {
                sp = format.Substring(2, 1);
                index = 0;
            }
            else
            {
                int spIndex = format.IndexOf(spvalue);
                sp = format.Substring(spIndex - 1, 1);
                index = 1;
            }
            bool isFH = code.StartsWith("-");
            if (isFH) code = code.Substring(1);
            string[] xys = code.Split(char.Parse(sp));
            if (xys.Length < 2) return -1;
            double v = 0;
            string sv = "";
            if (xys.Length == 2)
            {
                sv = xys[index];
                if (index == 1) isFH = false;
            }
            else if (xys.Length == 3)
            {
                if (index == 1)
                {
                    sv = xys[index + 1];
                    isFH = true;
                }
                else
                {
                    sv = xys[index];
                }
            }
            if (!double.TryParse(sv, out v)) return -1;
            if (isFH) v = v * (-1);
            v = v * UnitValue + offset;
            return v;
        }
        
        /// <summary>
        /// 获取匹配的字符串
        /// </summary>
        /// <param name="format">图号格式</param>
        /// <param name="value">要匹配的格式</param>
        /// <returns></returns>
        protected string GetMatchString(string format, string value)
        {
            Match m = Regex.Match(format, value);
            string str = "";
            while (m.Success)
            {
                str += m.Value;
                m = m.NextMatch();
            }
            return str.Trim();
        }

        /// <summary>
        /// 判断图幅与空间对象是否没有公共的部分
        /// </summary>
        /// <param name="polygon">要比较的图幅范围</param>
        /// <returns></returns>
        protected bool Disjoint(IPolygon polygon)
        {
            if (RelationalGeometry != null)
            {
                return RelationalGeometry.Disjoint(polygon);
            }
            if (RelationalFeatureClass != null)
            {
                ISpatialFilter flt = new SpatialFilter();
                flt.Geometry = polygon;
                flt.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
                IFeatureCursor cur = RelationalFeatureClass.Search(flt, false);
                IFeature feat = cur.NextFeature();
                bool isspace = false;
                if (feat == null)
                    isspace = true;
                if (feat != null)
                {
                    Marshal.ReleaseComObject(feat);
                    feat = null;
                }
                Marshal.ReleaseComObject(cur);
                cur = null;
                return isspace;
            }
            return false;
        }
                
        /// <summary>
        /// 获取大于value且为range的最小整数
        /// </summary>
        /// <param name="value"></param>
        /// <param name="range"></param>
        /// <returns></returns>
        protected double GetCeiling(double value, int range)
        {
            double v = value;
            if (value % range == 0)
            {
                v = value;
            }
            else
            {
                if (value >= 0)
                    v = ((int)(value / range) + 1) * range;
                else
                    v = ((int)(value / range) - 1) * range;
            }
            return v;
        }

        /// <summary>
        /// 获取小于value且为range的最大整数
        /// </summary>
        /// <param name="value"></param>
        /// <param name="range"></param>
        /// <returns></returns>
        protected double GetFloor(double value, int range)
        {
            double v = value;
            if (value % range == 0)
            {
                v = value;
            }
            else
            {
                if (value >= 0)
                    v = ((int)(value / range)) * range;
                else
                    v = ((int)(value / range) - 1) * range;
            }
            return v;
        }

        /// <summary>
        /// 根据2000比例尺的
        /// </summary>
        /// <param name="value">图号值</param>
        /// <param name="row"></param>
        /// <param name="col"></param>
        private void GetRowCol(int value, out int row, out int col)
        {
            row = 1;
            col = 1;
            for (int i = col; i <= 3; i++)
            {
                for (int j = row; j <= 3; j++)
                {
                    if ((i + (j - 1) * 3) == value)
                    {
                        row = j;
                        col = i;
                        return;
                    }
                }
            }
        }

        /// <summary>
        /// 根据国标计算公式计算图幅号
        /// </summary>
        /// <param name="lon">经度</param>
        /// <param name="lat">纬度</param>
        /// <param name="scalecode">比例尺编码</param>
        /// <returns></returns>
        private string MathSheetCode(double lon, double lat,string scalecode)
        {
            if (lon > 180 || lon < 0 || lat > 90 || lat < 0)
                throw new Exception("坐标值错误，不在经纬度范围内");
            char rowMillion = (char)((char)(lat / 4) + 'A');
            int colMillion = (int)(lon / 6) + 31;
            string strColMillion = colMillion.ToString().PadLeft(2, '0');
            if (Width == LonDiff)
                return rowMillion.ToString() + strColMillion;
            int row = (int)(((rowMillion - 'A' + 1) * 4 - lat) / Height) + 1;
            int col = (int)((lon - (colMillion - 31) * 6) / Width) + 1;
            string strRow = row.ToString().PadLeft(3, '0');
            string strCol = col.ToString().PadLeft(3, '0');
            return rowMillion.ToString() + strColMillion + scalecode.Trim() + strRow + strCol;
        }

        /// <summary>
        /// 根据国标计算公式计算西南角（左下角）点
        /// </summary>
        /// <param name="sheetcode">图幅编号</param>
        /// <returns></returns>
        protected IPoint MathBaseWSPoint(string sheetcode)
        {
            char rowMillion = sheetcode.Substring(0, 1).ToArray()[0];
            int colMillion = int.Parse(sheetcode.Substring(1, 2));
            int rowNo = 0;
            int colNo = 0;
            if (sheetcode.Length >= 10)
            {
                if (!int.TryParse(sheetcode.Substring(4, 3), out rowNo) || !int.TryParse(sheetcode.Substring(7, 3), out colNo))
                    throw new Exception("编号" + sheetcode + "不是标准的图幅编号，无法根据编号计算");
            }
            double lon = (colMillion - 31) * LonDiff + (colNo - 1) * Width;// 经度
            double lat = (rowMillion - 'A') * LatDiff + (LatDiff / Height - rowNo) * Height; //纬度
            if (sheetcode.Length > 10)
            {
                int code = int.Parse(sheetcode.Trim().Substring(sheetcode.Trim().Length - 1));
                int n = 1;
                int m = 1;
                GetRowCol(code, out m, out n);
                lon = lon + (n - 1) * Width / ColLength;
                lat = lat + (3 - m) * Height / RowLength;                
            }
            return new Point()
            {
                X = lon,
                Y = lat
            };
        }
    }

}
